//
//  TwitterClient.m
//  TuiTe
//
//  Created by 张 霄鹤 on 10-3-3.
//  Copyright 2010 xhzhang. All rights reserved.
// 

#import "TwitterClient.h"
#import "TwitterParser.h"
#import "Account.h"
#import "DataManager.h"

#import "Reachability.h"

#import "JSON.h"


#define TWSERVER @"http://vhlyserver.appspot.com/tw"
#define CALLBACKSERVER @"http://vhlyserver.appspot.com/tw?auth=ok"
#define SHORTURLSERVER @"http://vhlyserver.appspot.com/su"

#define CURRENTACCOUNTINDEX @"cu"


//

static TwitterClient *clientInstance;

@implementation TwitterClient

@synthesize account;
@synthesize screen_name;
@synthesize password;
@synthesize tokenInfo;

+ (TwitterClient *)getInstance{
	if(clientInstance == nil){
		NSUserDefaults *usrDefaults = [NSUserDefaults standardUserDefaults];
		NSInteger cu = [usrDefaults integerForKey:CURRENTACCOUNTINDEX];
		NSString *tu = nil;
		NSString *tp = nil;
		if(cu < 0){
			cu = 0;
		}
		DataManager *dm = [DataManager sharedManager];
		Account *acc = [dm getAccount:cu];
		if(acc){
			tu = acc.name;
			tp = acc.pass;
		}
		if(tu == nil){
			tu = @"vhly@163.com";
		}
		if(tp == nil){
			tp = @"fiverats";
		}
		clientInstance = [[TwitterClient alloc] initWithName:tu withPass:tp];
	}
	return clientInstance;
}

- (id)initWithName:(NSString *)acc withPass:(NSString *)pass{
	if(self = [super init]){
		self.account = acc;
		self.password = pass;
		// TODO For OAuth
		consumerKey = @"bOTAsQ6nHrBeyGdh3gTDA";
		consumerSecret = @"nx0K0AyciIMYVAoLiA04kUzoVXjXwG3KUUpUfbNYeKI";
	}
	return self;
}

- (void)changeAccount:(NSString *)acc withPass:(NSString *)pass{
	self.account = acc;
	self.password = pass;
	changed = YES;
}

- (void)setNetRef:(NSInteger)itype{
	UIApplication *app = [UIApplication sharedApplication];
	if(itype == 0){
		netRefCount--;
	}else if(itype == 1){
		netRefCount++;
	}
	app.networkActivityIndicatorVisible = netRefCount > 0;
}

- (BOOL)doStatusesRetweet:(NSDictionary *)params{
	BOOL ret = NO;
	if(params){
		if([params count] > 0){
			TwRequest *req = [[TwRequest alloc] init];
			req.category = CATEGORY_STATUS;
			req.method = METHOD_STATUSES_RETWWEET;
			req.httpMethod = HTTP_API_POST;
			req.hasID = 1;
			req.authType = AUTH_TYPE_BASIC;
			req.authData = [self genAuthData];
			[req putParams:params];
			TwResponse *resp;//  = [self invokeTW:req];
			BOOL bok = [self invokeTW:req retResponse:&resp];
			[req release];
			if(bok){
				// 对于不需要使用返回值的，直接检测状态码即可
				//NSString *xml = [self processResponse:resp];
//				if(xml){
//					ret = YES;
//				}
				if(resp.state == 200){
					ret = YES;
				}
				[resp release];
			}
			
		}
	}
	return ret;
}

- (BOOL)doStatusesUpdate:(NSDictionary *)params{
	BOOL ret = NO;
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_STATUS;
	req.method = METHOD_STATUSES_UPDATE;
	req.httpMethod = HTTP_API_POST;
	req.authType = AUTH_TYPE_BASIC;
	req.authData = [self genAuthData];
	[req putParams:params];
	TwResponse *resp; // = [self invokeTW:req];
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		// 对于不需要使用返回值的，直接检测状态码即可
		//NSString *xml = [self processResponse:resp];
		//				if(xml){
		//					ret = YES;
		//				}
		if(resp.state == 200){
			ret = YES;
		}
		[resp release];
	}
	return ret;
}

#pragma mark -
#pragma mark UserManager

- (NSArray *)doFriendShipIDS:(NSInteger)iType withCursor:(NSString *)cursor{
	NSArray *ret = nil;
	TwRequest *req = [[TwRequest alloc] init];
	// 由于 friends followers 属于一个类别，因此使用 Social_graph代表
	
	req.category = CATEGORY_SOCIAL_GRAPH;
	
	if(iType == 0){
		req.method = METHOD_FRIENDS;
	}else if(iType == 1){
		req.method = METHOD_FOLLOWERS;
	}
	req.format = FORMAT_TYPE_XML;
	if(cursor){
		[req putParam:cursor forKey:@"cursor"];
	}else{
		[req putParam:@"-1" forKey:@"cursor"];
	}
	// TODO 注释掉这个部分进行测试
	req.authType = AUTH_TYPE_BASIC;
	req.authData = [self genAuthData];
	
	TwResponse *resp;//  = [self invokeTW:req];
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		[resp release];
		if(xml){
			ret = [TwitterParser parseFriendshipIDs:xml];
		}else{
			NSLog(@"Request Error");
		}
	}
	return ret;
}

/**
 * 检查是否from follow to了
 * @param from is user_a
 * @param to   is user_b
 * @return BOOL
 */
- (BOOL)doFriendShipExists:(NSString *)from withFollow:(NSString *)to{
	BOOL bret = NO;
	if (from && to) {
		TwRequest *req = [[TwRequest alloc] init];
		req.category = CATEGORY_FRIENDSHIPS;
		req.method = METHOD_FRIENDSHIP_EXISTS;
		req.authType = AUTH_TYPE_BASIC;
		req.authData = [self genAuthData];
		req.httpMethod = HTTP_API_GET;
		[req putParam:from forKey:@"user_a"];
		[req putParam:to forKey:@"user_b"];
		TwResponse *resp;//  = [self invokeTW:req];
		BOOL bok = [self invokeTW:req retResponse:&resp];
		[req release];
		if(bok){
			NSString *xml = [self processResponse:resp];
			[resp release];
			if(xml){
				bret = YES;
			}else{
				bret = NO;
				NSLog(@"Request Error");
			}
		}
	}
	return bret;
}

/**
 * Follow 某人
 * @param uid 用户ID, 绝对数字形式ID
 * @return User1 Follow之后的信息
 */
- (id)doFriendShipCreate:(NSString *)uid{
	User1 *ret = nil;
	if (uid) {
		TwRequest *req = [[TwRequest alloc] init];
		req.category = CATEGORY_FRIENDSHIPS;
		req.method = METHOD_FRIENDSHIP_CREATE;
		req.authType = AUTH_TYPE_BASIC;
		req.authData = [self genAuthData];
		req.httpMethod = HTTP_API_POST;
		req.hasID = 1;
		[req putParam:uid forKey:@"tt_id"];
		TwResponse *resp;//  = [self invokeTW:req];
		BOOL bok = [self invokeTW:req retResponse:&resp];
		[req release];
		if(bok){
			NSString *xml = [self processResponse:resp];
			[resp release];
			if(xml){
				ret = [TwitterParser parseUser:xml];
			}else{
				NSLog(@"Request Error");
			}
		}
	}
	return ret;
}

/**
 * 查询用户
 */
- (NSArray *)doUserSearch:(NSString *)uname withPage:(NSInteger)page{
	NSArray *ret = nil;
	if(uname){
		TwRequest *req = [[TwRequest alloc] init];
		req.category = CATEGORY_USERS;
		req.method = METHOD_USERS_SEARCH;
		req.authType = AUTH_TYPE_BASIC;
		req.authData = [self genAuthData];
		[req putParam:uname forKey:@"q"];
		if (page > 1) {
			[req putParam:[NSString stringWithFormat:@"%d",page] forKey:@"page"];
		}
		TwResponse *resp;//  = [self invokeTW:req];
		BOOL bok = [self invokeTW:req retResponse:&resp];
		[req release];
		if(bok){
			NSString *xml = [self processResponse:resp];
			[resp release];
			if(xml){
				ret = [TwitterParser parseUsers:xml];
			}else{
				NSLog(@"Request Error");
			}
		}
	}
	return ret;
}

- (id)doUserShow:(NSString *)uname{
	id ret = nil;
	if(uname){
		TwRequest *req = [[TwRequest alloc] init];
		req.category = CATEGORY_USERS;
		req.method = METHOD_USERS_SHOW;
		req.authType = AUTH_TYPE_BASIC;
		req.authData = [self genAuthData];
		[req putParam:uname forKey:@"id"];
		TwResponse *resp;//  = [self invokeTW:req];
		BOOL bok = [self invokeTW:req retResponse:&resp];
		[req release];
		if(bok){
			NSString *xml = [self processResponse:resp];
			[resp release];
			if(xml){
				// TODO Parse xml
				ret = [TwitterParser parseUser:xml];
#ifdef DEBUG
				NSLog(@"User Info = %@",xml);
#endif
			}else{
				NSLog(@"Request Error");
			}
		}
	}
	return ret;
}

#pragma mark -
#pragma mark Search

/**
 * 查询Tweets
 *
 */
- (NSArray *)doSearch:(NSString *)query  withPage:(NSInteger)page{
	NSArray *ret = nil;
	if(query){
		TwRequest *req = [[TwRequest alloc] init];
		req.category = CATEGORY_SEARCH;
		req.method = METHOD_SEARCH_KEYWORD;
		req.format = FORMAT_TYPE_ATOM;
		[req putParam:query forKey:@"q"];
		if (page > 1) {
			[req putParam:[NSString stringWithFormat:@"%d",page] forKey:@"page"];
		}
		TwResponse *resp;//  = [self invokeTW:req];
		BOOL bok = [self invokeTW:req retResponse:&resp];
		[req release];
		if(bok){
			NSString *xml = [self processResponse:resp];
			[resp release];
			if(xml){
				ret = [TwitterParser parseSearchATOM:xml];
			}else{
				NSLog(@"Request Error");
			}
		}
	}
	return ret;
}

- (void)doTrends:(NSMutableArray *)arrTarget{
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_SEARCH;
	req.method = METHOD_SEARCH_TREND;
	req.format = FORMAT_TYPE_JSON;
	TwResponse *resp = nil;
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *json = [self processResponse:resp];
		[resp release];
		if(json){
			// TODO 解析JSON
			NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
			SBJSON *sb = [[SBJSON alloc] init];
			id obj = [sb objectWithString:json];
			
			if(obj){
				if([obj isKindOfClass:[NSDictionary class]]){
					NSDictionary *dict = (NSDictionary *)obj;
					obj = [dict objectForKey:@"trends"];
					if(obj){
						if([obj isKindOfClass:[NSArray class]]){
							NSArray *array = (NSArray *)obj;
							[arrTarget setArray:array];
						}
					}
				}
			}
			[sb release];
			[pool release];
		}else{
			NSLog(@"Trends Request Error");
		}
	}
}



#pragma mark -
#pragma mark TimeLine


- (NSArray *)doStatusesFriendTimeLineWithSinceID:(NSString *)sinceID{
	NSArray *ret = nil;
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_STATUS;
	req.method = METHOD_STATUSES_FRIENDS_TIMELINE;
	req.authType = AUTH_TYPE_BASIC;
	req.authData = [self genAuthData];
	if(sinceID){
		[req putParam:sinceID forKey:@"since_id"];
	}
	TwResponse *resp;//  = [self invokeTW:req];
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		[resp release];
		if(xml){
			ret = [TwitterParser parseStatuses:xml];
		}else{
			NSLog(@"Request Error");
		}
	}
	return ret;
}

- (NSArray *)doStatusesHomeTimeLineWithSinceID:(NSString *)sinceID{
	NSArray *ret = nil;
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_STATUS;
	req.method = METHOD_STATUSES_HOME_TIMELINE;
	//req.authType = AUTH_TYPE_BASIC;
	req.authType = AUTH_TYPE_OAUTH;
	[req putOAuthParam:self.tokenInfo.token forKey:REQ_TOKEN];
	[req putOAuthParam:self.tokenInfo.tokenSecret forKey:REQ_TOKEN_SECRET];
	// req.authData = [self genAuthData];
	if(sinceID){
		[req putParam:sinceID forKey:@"since_id"];
	}
	TwResponse *resp;
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		[resp release];
		if(xml){
			ret = [TwitterParser parseStatuses:xml];
		}else{
			NSLog(@"Request Error");
		}
	}
	return ret;
}

- (NSArray *)doStatusesMentions:(NSString *)sinceID{
	NSArray *ret = nil;
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_STATUS;
	req.method = METHOD_STATUSES_MENTIONS;
	req.authType = AUTH_TYPE_BASIC;
	req.authData = [self genAuthData];
	if(sinceID){
		[req putParam:sinceID forKey:@"since_id"];
	}
	TwResponse *resp;
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		[resp release];
		if(xml){
			ret = [TwitterParser parseStatusesNotWithCoreData:xml];
		}else{
			NSLog(@"Request Error");
		}
	}
	return ret;
}

- (NSArray *)doStatusesPublicTimeLine{
	NSArray *ret = nil;
	if (self.tokenInfo == nil || self.tokenInfo.token == nil) {
		NSLog(@"Error NO Auth");
		return nil;
	}
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_STATUS;
	req.method = METHOD_STATUSES_PUBLIC_TIMELINE;
	TwResponse *resp;
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		if(xml){
			ret = [TwitterParser parseStatuses:xml];
		}else{
			NSLog(@"Request Error");
		}
		[resp release];
	}
	return ret;
}

#pragma mark -
#pragma mark OAuthSupport
/*
 Twitter OAuth
 
 1. Perform a request token request using HTTPS, POST, the following variables and the consumer secret "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98":
 oauth_callback
 - http://localhost:3005/the_dance/process_callback?service_provider_id=11
 oauth_consumer_key
 - GDdmIQH6jhtmLUypg82g
 oauth_nonce
 - QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk
 oauth_signature_method
 - HMAC-SHA1
 oauth_timestamp
 - 1272323042
 oauth_version
 - 1.0
 
 */

- (NSString *)doOAuthRequestToken{
	NSString *ret = nil;
	TwRequest *req = [[TwRequest alloc] init];
	req.category = CATEGORY_OAUTH;
	req.method = METHOD_OAUTH_REQUEST_TOKEN;
	req.httpMethod = HTTP_API_POST;
	req.format = FORMAT_TYPE_NONE;
	req.authType = AUTH_TYPE_OAUTH;
	TwResponse *resp;
	BOOL bok = [self invokeTW:req retResponse:&resp];
	[req release];
	if(bok){
		NSString *xml = [self processResponse:resp];
		if(xml){
			NSRange rang = [xml rangeOfString:@"&"];
			if (rang.location != NSNotFound) {
				NSString *s1 = [xml substringToIndex:rang.location];
				NSString *s2 = [xml substringFromIndex:(rang.location + rang.length)];
#ifdef DEBUG
				NSLog(@"Token is %@ Secret is %@",s1,s2);
#endif
				rang = [s1 rangeOfString:@"="];
				NSString *token = nil;
				NSString *secret = nil;
				if (rang.location != NSNotFound) {
					token = [s1 substringFromIndex:(rang.location + rang.length)];
				}
				rang = [s2 rangeOfString:@"="];
				if (rang.location != NSNotFound) {
					secret = [s2 substringFromIndex:(rang.location + rang.length)];
				}
				if (secret && token) {
					OAuthToken *oatoken = [[OAuthToken alloc] init];
					oatoken.token = token;
					oatoken.tokenSecret = secret;
					self.tokenInfo = oatoken;
					[oatoken release];
					ret = self.tokenInfo.token;
				}
			}
		}else{
			NSLog(@"Request Error");
		}
		[resp release];
	}
	return ret;
}

/*
 TuiTe
 
 Consumer key
	bOTAsQ6nHrBeyGdh3gTDA
 Consumer secret
	nx0K0AyciIMYVAoLiA04kUzoVXjXwG3KUUpUfbNYeKI
 
 */

#pragma mark -


- (BOOL)invokeTW:(TwRequest *)req retResponse:(TwResponse **)tresp{
	BOOL ret = NO;
	if(req){
		// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//		NetworkStatus st = [[Reachability reachabilityForInternetConnection] currentReachabilityStatus];
//		// [pool release];
//		
//		if (st == NotReachable) {
//			// TODO 提示联网问题
//			return NO;
//		}
		
		if ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == NotReachable) {
			// TODO 提示联网问题
			if (alert == nil) {
				alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"No Connection" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
			}
			[alert setMessage:@"No Connection"];
			[alert setTitle:@"Error"];
			[alert show];
			return NO;
		}
		
		NSData *body = [req getRequestData];
		if(body){
			DataManager *dm = [DataManager sharedManager];
			NSString *pr = dm.proxyAddress;
			if(pr == nil){
				dm.proxyAddress = TWSERVER;
				pr = TWSERVER;
			}
			NSURL *url = [[NSURL alloc] initWithString:pr];
			NSMutableURLRequest *rq = [[NSMutableURLRequest alloc] initWithURL:url];
			[rq setTimeoutInterval:60];
			[rq setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
			[rq addValue:@"gzip" forHTTPHeaderField:@"User-Agent"];
			NSString *sl = [[NSString alloc] initWithFormat:@"%d",[body length]];
			[rq addValue:sl forHTTPHeaderField:@"Content-Length"];
			[sl release];
			[rq setHTTPBody:body];
			[rq setHTTPMethod:@"POST"];
			NSHTTPURLResponse *hresp;
			NSError *err;
			
			[self setNetRef:1];
	
			NSData *d = [NSURLConnection sendSynchronousRequest:rq returningResponse:&hresp error:&err];
			[self setNetRef:0];
			if(d == nil && err != nil){
				NSLog(@"Error: %@",[err localizedDescription]);
				[err release];
			}else{
				NSLog(@"OK");
				(*tresp) = [[TwResponse alloc] init];
				(*tresp).state = [hresp statusCode];
				[(*tresp) appendData:d];
				[hresp release];
				ret = YES;
			}
			[rq release];
			[url release];			
		}
	}
	return ret;
}

- (NSString *)processResponse:(TwResponse *)resp{
	NSString *ret = nil;
	if(resp){
		if(resp.state == 200){
			if(resp.data){
				ret = [[[NSString alloc] initWithData:resp.data encoding:NSUTF8StringEncoding] autorelease];
			}
		}else{
			if(resp.data){
				NSString *ds = [[NSString alloc] initWithData:resp.data encoding:NSUTF8StringEncoding];
#ifdef DEBUG
				NSLog(@"Error Resp xml is = %@",ds);
#endif
				[ds release];
			}
		}
	}
	return ret;
}

- (NSData *)genAuthData{
	if(authData == nil || changed){
		authData = [[NSMutableData alloc] init];
		NSString *ac = [[NSString alloc] initWithFormat:@"%@:%@",account,password];
		// [NSString stringWithFormat:@"%@:%@",account,password];
		//NSData *d1 = [ac dataUsingEncoding:NSUTF8StringEncoding];
//		NSInteger len = [d1 length];
//		char *buf = (char *)[d1 bytes];
//		for(int i = len - 1; i>=0;i--){
//			buf[i] ^= i;
//		}
//		[authData appendBytes:buf length:len];
		// TODO 检查下面的代码能否正常工作
		char *buf = (char *)[ac cStringUsingEncoding:NSUTF8StringEncoding];
		NSInteger len = strlen(buf);
		for(int i = len - 1; i>=0;i--){
			buf[i] ^= i;
		}
		[authData appendBytes:buf length:len];
		[ac release];
		buf = nil;
		changed = NO;
	}
	return authData;
}

+ (NSString *)shortenURL:(NSString *)url{
	if ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == NotReachable) {
		// TODO 提示联网问题
		return nil;
	}
	
	NSString *ret = nil;
	
	DataManager *dm = [DataManager sharedManager];
	NSString *svn = [dm getShortenURLSettingName];
	NSString *su = [[NSString alloc] initWithFormat:@"%@?f=txt&sv=%@&u=%@",SHORTURLSERVER,svn,url];
	NSURL *u = [[NSURL alloc] initWithString:su];
	[su release];
	NSMutableURLRequest *rq = [[NSMutableURLRequest alloc] initWithURL:u];
	[rq setTimeoutInterval:60];
	NSHTTPURLResponse *hresp;
	NSError *err;
	UIApplication *app = [UIApplication sharedApplication];
	app.networkActivityIndicatorVisible = YES;
	NSData *d = [NSURLConnection sendSynchronousRequest:rq returningResponse:&hresp error:&err];
	app.networkActivityIndicatorVisible = NO;
	if(d == nil && err != nil){
		[err release];
	}else{
		if([hresp statusCode] == 200){
			if(d){
				ret = [[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] autorelease];
			}
		}
	}
	[rq release];
	[u release];
	
	return ret;
}



- (void)dealloc{
	[account release];
	[password release];
	if(screen_name){
		[screen_name release];
	}
	if(authData){
		[authData release];
	}
	if (alert) {
		[alert release];
	}
	[tokenInfo release];
	[super dealloc];
}

@end
